﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using nwrole.lib;

namespace nwrole.service
{
    internal enum ServiceManagerInstanceState
    {
        Running,
        Halted
    }

    [Serializable]
    internal class DomainResolver
    {
        public string PluginDirectory { get; set; }
        public string InstanceDirectory { get; set; }
        public string ServiceDirectory { get; set; }
        public string SolutionDirectory { get; set; }

        public Assembly AssemblyResolveEvent (object sender, ResolveEventArgs args)
        {
            EventLogger.LogInformation("DomainResolver.AssemblyResolveEvent", args.Name);
            string name = args.Name;
            if (name.Contains(','))
                name = name.Split(',').First().Trim();
            if (!name.EndsWith(".dll"))
                name += ".dll";
            return Assembly.LoadFile(Path.Combine(PluginDirectory, name));
        }
    }

    internal class ServiceManagerInstance
    {
        public Plugin Plugin { get; private set; }
        public Solution.Instance Instance { get; private set; }
        public Solution.Service Service { get; private set; }
        public Solution Solution { get; private set; }

        public Assembly Assembly { get; private set; }
        public Type PluginType { get; private set; }
        public PluginBase Object { get; private set; }

        public ServiceManagerInstanceState State { get; private set; }

        public ServiceManagerInstance (Plugin plugin, Solution.Instance instance, Solution.Service service, Solution solution)
        {
            Plugin = plugin;
            Instance = instance;
            Service = service;
            Solution = solution;
            State = ServiceManagerInstanceState.Halted;

            DomainResolver resolver = new DomainResolver
            {
                PluginDirectory = PluginDirectoryPath(Plugin),
                InstanceDirectory = InstanceDirectoryPath(Instance),
                ServiceDirectory = ServiceDirectoryPath(Service),
                SolutionDirectory = SolutionDirectoryPath(Solution)
            };

            AppDomain domain = AppDomain.CurrentDomain;
            domain.SetupInformation.ApplicationBase = InstanceDirectoryPath(instance);
            domain.AssemblyResolve += new ResolveEventHandler(resolver.AssemblyResolveEvent);

            Object = (PluginBase)domain.CreateInstanceAndUnwrap(Plugin.Assembly, Plugin.ClassName);
            Object.Initialize(plugin, instance, service, solution);
            
            /*Assembly = Assembly.LoadFile(Path.Combine(PluginDirectoryPath(Plugin), Plugin.Assembly));
            PluginType = Assembly.GetType(Plugin.ClassName);
            Object = Activator.CreateInstance(PluginType);

            MethodInfo method = typeof(PluginBase).GetMethod("Initialize", BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.InvokeMethod);
            method.Invoke(Object, new object[]
            {
                plugin,
                instance,
                service,
                solution
            });*/
        }

        public void StartInstance ()
        {
            State = ServiceManagerInstanceState.Running;
            Object.Start();
        }

        public void StopInstance ()
        {
            State = ServiceManagerInstanceState.Halted;
            Object.Stop();
        }

        #region Static
        public static string SolutionDirectoryPath (Solution solution)
        {
            return Path.Combine(Configuration.SolutionsDirectory, solution.Id.ToString("N"));
        }

        public static string PluginDirectoryPath (Plugin plugin)
        {
            return Path.Combine(Configuration.PluginsDirectory, plugin.Id.ToString("N"));
        }

        public static string ServiceDirectoryPath (Solution.Service service)
        {
            string path = Path.Combine(Configuration.SolutionsDirectory, service.Id.ToString("N"));
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            return path;
        }

        public static string InstanceDirectoryPath (Solution.Instance instance)
        {
            string path = Path.Combine(Configuration.SolutionsDirectory, instance.Id.ToString("N"));
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            return path;
        }
        #endregion
    }
}
